package utils

import (
	"encoding/json"
	"fmt"
	"github.com/google/uuid"
	"io"
	"log"
	"net"
	"net/http"
	"reflect"
	"runtime"
	"strconv"
	"strings"
)

const xForwardedFor = "X-Forwarded-For"

func getCaller(callDepth int) string {
	_, file, line, ok := runtime.Caller(callDepth)
	if !ok {
		return ""
	}
	return prettyCaller(file, line)
}

func prettyCaller(file string, line int) string {
	idx := strings.LastIndexByte(file, '/')
	if idx < 0 {
		return fmt.Sprintf("%s:%d", file, line)
	}

	idx = strings.LastIndexByte(file[:idx], '/')
	if idx < 0 {
		return fmt.Sprintf("%s:%d", file, line)
	}

	return fmt.Sprintf("%s:%d", file[idx+1:], line)
}

func Close(c io.Closer) {
	err := c.Close()
	if err != nil {
		log.Printf("io close error %v", err)
	}
}

func GetLocalIP() string {
	addrArr, err := net.InterfaceAddrs()
	if nil != err {
		return ""
	}
	for _, addr := range addrArr {
		ipNet, ok := addr.(*net.IPNet)
		if ok && !ipNet.IP.IsLoopback() &&
			ipNet.IP.To4() != nil {
			return ipNet.IP.String()
		}
	}
	return ""
}

// CopyBean 使用 JSON 序列化的方式进行拷贝，支持匿名字段，支持类型转换。
func CopyBean(srcPtr, dstPtr interface{}) error {
	bytes, err := json.Marshal(srcPtr)
	if err != nil {
		return err
	}
	return json.Unmarshal(bytes, dstPtr)
}

// GetRemoteAddr returns the peer address, supports X-Forward-For.
func GetRemoteAddr(r *http.Request) string {
	v := r.Header.Get(xForwardedFor)
	if len(v) > 0 {
		return v
	}
	return r.RemoteAddr
}

// 计算分页页码
func CalculatePage(total, size int) int {
	return (total + size - 1) / size
}

// 下划线写法转为驼峰写法
func Case2Camel(name string) string {
	name = strings.Replace(name, "_", " ", -1)
	name = strings.Title(name)
	return strings.Replace(name, " ", "", -1)
}

func GetKind(val reflect.Value) reflect.Kind {
	kind := val.Kind()

	switch {
	case kind >= reflect.Int && kind <= reflect.Int64:
		return reflect.Int
	case kind >= reflect.Uint && kind <= reflect.Uint64:
		return reflect.Uint
	case kind >= reflect.Float32 && kind <= reflect.Float64:
		return reflect.Float32
	default:
		return kind
	}
}

func IsBlank(value reflect.Value) bool {
	switch value.Kind() {
	case reflect.String:
		return value.Len() == 0
	case reflect.Bool:
		return !value.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return value.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return value.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return value.Float() == 0
	case reflect.Interface, reflect.Ptr:
		return value.IsNil()
	}
	return reflect.DeepEqual(value.Interface(), reflect.Zero(value.Type()).Interface())
}

// get a random UUID.
func GetUUID() string {
	u, err := uuid.NewRandom()
	if err != nil {
		log.Println(err)
	}
	return u.String()
}

// 字符串转int
func StringToInt(v string) int {
	res, err := strconv.Atoi(v)
	if err != nil {
		return 0
	}
	return res
}

// 字符串转uint
func StringToUint(v string) uint {
	res, err := strconv.Atoi(v)
	if err != nil {
		return uint(0)
	}
	return uint(res)
}
